// -----------
// Copyright (c) 2020. RISC-V International. All rights reserved.
// SPDX-License-Identifier: BSD-3-Clause
// -----------
//
// This test belongs to the test plan for RISC-V Privilege Arch Compliance developed by 10xEngineers
// which can be found here: https://docs.google.com/spreadsheets/d/1p13gic7BD6aq7n_dHrqti4QmlGpxY7FkF17RVbG4DC0/edit?usp=sharing
//
// This assembly file tests access of pmp registers in M, S, and U mode.
// pmp csrs are accessable only in M-mode so it should trap in S, and U mode.
//
/* COVERPOINTS: (Explanation of updates in /coverage/rv32i_priv.cgf)

// Details are given in /coverage/rv32i_priv.cgf
*/
// 
#define rvtest_strap_routine
#include "model_test.h"
#include "arch_test.h"
RVTEST_ISA("RV32I_Zicsr")
# Test code region
.section .text.init
.globl rvtest_entry_point
rvtest_entry_point:
RVMODEL_BOOT
RVTEST_CODE_BEGIN
#ifdef TEST_CASE_1
    RVTEST_CASE(1,"//check ISA:=regex(.*32.*); check ISA:=regex(.*I.*Zicsr.*); def rvtest_mtrap_routine=True; def TEST_CASE_1=True",PMP_access_permission)
RVTEST_SIGBASE( x13,signature_x13_1)
	.option nopic
	.attribute unaligned_access, 0
	.attribute stack_align, 16
  	.align	2    
main: 
#define PMPCFG0		0x3A0		// Address of pmpcfg0 	(HAS BEEN USED WHILE ITERATING THE LOOP)
#define PMPADDR0	0x3B0		// Address of pmpaddr0 	(HAS BEEN USED WHILE ITERATING THE LOOP)
main:
//////////////////////// INITIAL VALUES //////////////////////////////// 
    	LI(a5, -1)		// SEtting up All locked bits (including everyother non-zero bit, which is redundent for this test)
    	LI(x5, 100)		// A rondom number, to check if pmp regs get update after lock bit enable
	// Loop to SET ALL pmpcfg REGs to zero
	.set pmpcfgi, PMPCFG0	// Initialize an iterating variable with the address of pmpcfg0
	.rept 4			// START OF LOOP
	csrc pmpcfgi , a5	// Set all pmpcfg regs to zero (initial value)
	.set pmpcfgi, pmpcfgi+1		// increment variable to next pmpcfg reg
	.endr			// END OF LOOP BODY
	// Loop to SET ALL pmpaddr REGs to zero
	// Loop to SET ALL pmpaddr REGs to zero
	.set pmpaddri, PMPADDR0	// Initialize an iterating variable with the address of pmpaddr0
	.rept 16		// START OF LOOP
	csrc pmpaddri, a5	// Set all pmpaddr regs to zero (initial value)
	.set pmpaddri, pmpaddri+1		// increment variable pmpaddri to the next pmpaddr reg
	.endr			// END OF LOOP BODY
	.set pmpaddri, PMPADDR0	// Initialize an iterating variable with the address of pmpaddr0
	.rept 16		// START OF LOOP
	csrs pmpaddri, a5	// Set all pmpaddr regs to zero (initial value)
	.set pmpaddri, pmpaddri+1		// increment variable pmpaddri to the next pmpaddr reg
	.endr			// END OF LOOP BODY
//////////////// VERIFICATION /////////////////////////////////////////
// READING pmpaddr in M-mode /////////////////////////////////////////
	.set pmpaddri, PMPADDR0		// Initialize an iterating variable with the address of pmpaddr0
	.rept 16			// START OF LOOP
	csrr a4, pmpaddri		// READING pmpaddri (i is from 0-15)
	nop				// Added nop in case of trap
	RVTEST_SIGUPD(x13,a4)		// Storing into signature file
	.set pmpaddri, pmpaddri+1		// increment variable pmpaddri to the next pmpaddr reg
	.endr			// END OF LOOP BODY
// WRITING pmpcfg registers //////////////////////////////////////////
// Write in M-mode will be valid, Write in other modes will cause trap
	LI(a5, PMP_R| PMP_W | PMP_X | PMP_TOR)	// LOCKED BIT IS NOT SET
	// Loop to Write ALL pmpcfg regs
	.set pmpcfgi, PMPCFG0	// Initialize an iterating variable with the address of pmpcfg0
	.rept 4			// START OF LOOP
	csrw pmpcfgi, a5			// Write pmpcfgi
	nop					// Added nop in case of trap
	.set pmpcfgi, pmpcfgi+1		// increment variable to next pmpcfg reg
	.endr			// END OF LOOP BODY
//////////////// VERIFICATION /////////////////////////////////////////
// READING pmpcfg in M-mode /////////////////////////////////////////
	// Loop to verify the contents of pmpcfg regs
	.set pmpcfgi, PMPCFG0		// Initialize an iterating variable with the address of pmpcfg0
	.rept 4				// START OF LOOP
	csrr a4, pmpcfg0		// Read pmpcfg0
	nop				// Added nop in case of trap
	RVTEST_SIGUPD(x13,a4)
	.set pmpcfgi, pmpcfgi+1		// increment variable to next pmpcfg reg
	.endr			// END OF LOOP BODY
/////////////////// Switch to S-mode ////////////////////////////////////////////
	csrw satp, zero                // Disable address translation.
	LI(t2, -1)
	csrw pmpaddr0, t2		// Updated pmpaddr0 to define PMP region consisting
					// of whole physical memory
	csrr t0, pmpaddr0		// Verify its value by reading back
	nop				// Added nop in case of trap
	RVTEST_SIGUPD(x13,t0)
	nop				// Added nop in case of trap
	LI(a5, PMP_L| PMP_R| PMP_W | PMP_X | PMP_TOR)		// LOCKED BIT IS SET
	csrw pmpcfg0, a5

	RVTEST_GOTO_LOWER_MODE	Smode	// GO into S mode	
// REPEATING THE SAME TEST //////////////////////////////////////////		
// IN Smode now
/////////////////// TEST 01 ////////////////////////////////////////////
// WRITING pmpaddr registers //////////////////////////////////////////
// Write in M-mode will be valid, Write in other modes will cause trap  	
	csrw pmpaddr0, x2		// Write pmpaddr0 in S mode (TRAP)
	nop				// Added nop in case of trap
// READING pmpaddr in S-mode /////////////////////////////////////////
	csrr a4, pmpaddr0		// Reading pmpaddr0 in S mode (TRAP)
	nop				// Added nop in case of trap
/////////////////// Switch back to M-mode ////////////////////////////////////////////
	RVTEST_GOTO_MMODE
  	csrr a4, mstatus		// VERIFICATION of M-mode
	nop				// Added nop in case of trap
	RVTEST_SIGUPD(x13,a4)
/////////////////// Switch to U-mode ////////////////////////////////////////////
	csrw satp, zero                 // Disable address translation.
	LI(t2, -1)
	csrw pmpaddr0, t2		// Updated pmpaddr0 to define PMP region consisting
					// of whole physical memory
	csrr t0, pmpaddr0		// Verify its value by reading back
	nop				// Added nop in case of trap
	RVTEST_SIGUPD(x13,t0)
	nop				// Added nop in case of trap
	LI(a5, PMP_L| PMP_R| PMP_W | PMP_X | PMP_TOR)		// LOCKED BIT IS SET
	csrw pmpcfg0, a5
// These steps are repeated and can be removed but it will make sure that you will switch mode
// with full access on physical memory
	RVTEST_GOTO_LOWER_MODE	Umode	
// REPEATING THE SAME TEST //////////////////////////////////////////		
// IN U-mode now
/////////////////// TEST 01 ////////////////////////////////////////////
// WRITING pmpaddr registers //////////////////////////////////////////
// Write in M-mode will be valid, Write in other modes will cause trap  	
	csrw pmpaddr0, x2		// Write pmpaddr0 in u mode (TRAP)
	nop				// Added nop in case of trap
//////////////// VERIFICATION /////////////////////////////////////////
// READING pmpaddr in S-mode /////////////////////////////////////////
	csrr a4, pmpaddr0		// Reading pmpaddr0 in U mode (TRAP)
	nop				// Added nop in case of trap
	
#endif

 # ---------------------------------------------------------------------------------------------
    # HALT
RVTEST_CODE_END
RVMODEL_HALT

RVTEST_DATA_BEGIN
.align 4

rvtest_data:
.word 0xbabecafe
.word 0xbabecafe
.word 0xbabecafe
.word 0xbabecafe
RVTEST_DATA_END


RVMODEL_DATA_BEGIN
rvtest_sig_begin:
sig_begin_canary:
CANARY;
signature_x13_1:
    .fill 32*(XLEN/32),4,0xdeadbeef

#ifdef rvtest_mtrap_routine

tsig_begin_canary:
CANARY;
mtrap_sigptr:
    .fill 64*(XLEN/32),4,0xdeadbeef
tsig_end_canary:
CANARY;

#endif

#ifdef rvtest_gpr_save

gpr_save:
    .fill 32*(XLEN/32),4,0xdeadbeef

#endif

sig_end_canary:
CANARY;
rvtest_sig_end:
RVMODEL_DATA_END